package repositories

import (
	"fmt"
	"reflect"
	"strings"

	"gitee.com/kessil/chicory/internal/utils"
	"xorm.io/xorm"
)

type Repository[T any] struct {
	db *xorm.Engine
}

func NewRepository[T any](db *xorm.Engine) *Repository[T] {
	return &Repository[T]{db: db}
}

func (r *Repository[T]) GetByID(id int64) (*T, error) {
	var entity T
	has, err := r.db.ID(id).Get(&entity)
	if err != nil {
		return nil, err
	}
	if !has {
		return nil, fmt.Errorf("entity not found")
	}
	return &entity, nil
}

func (r *Repository[T]) GetOne(condition *T) (*T, error) {
	var entity T
	has, err := r.db.Get(&entity)
	if err != nil {
		return nil, err
	}
	if !has {
		return nil, fmt.Errorf("entity not found")
	}
	return &entity, nil
}

func (r *Repository[T]) GetMany(condition *T, pageNo, pageSize int) ([]T, int64, error) {
	var entities []T
	session := r.db.NewSession()

	if condition != nil {
		session = session.Where(condition)
	}

	total, err := session.Count(new(T))
	if err != nil {
		return nil, 0, err
	}

	if pageNo > 0 && pageSize > 0 {
		session = session.Limit(pageSize, (pageNo-1)*pageSize)
	}

	err = session.Find(&entities)
	if err != nil {
		return nil, 0, err
	}

	return entities, total, nil
}

func (r *Repository[T]) GetAll(condition *T) ([]T, int64, error) {
	var entities []T
	session := r.db.NewSession()

	if condition != nil {
		session = session.Where(condition)
	}

	total, err := session.Count(new(T))
	if err != nil {
		return nil, 0, err
	}

	err = session.Find(&entities)
	if err != nil {
		return nil, 0, err
	}

	return entities, total, nil
}

func (r *Repository[T]) Create(entity *T) error {
	_, err := r.db.Insert(entity)
	return err
}

func (r *Repository[T]) Update(id int64, entity *T) error {
	_, err := r.db.ID(id).Update(entity)
	return err
}

func (r *Repository[T]) Delete(id int64) error {
	_, err := r.db.ID(id).Delete(new(T))
	return err
}

func (r *Repository[T]) Exists(condition *T) (bool, error) {
	return r.db.Exist(condition)
}

func (r *Repository[T]) Count(condition *T) (int64, error) {
	return r.db.Where(condition).Count(new(T))
}

// Patch 部分更新
func (r *Repository[T]) Patch(id int64, updateData map[string]interface{}, ignoreFields []string) error {
	// 获取现有数据
	existing, err := r.GetByID(id)
	if err != nil {
		return err
	}

	// 应用Patch更新
	if err := utils.PatchUpdate(existing, updateData, ignoreFields); err != nil {
		return err
	}

	// 保存更新
	_, err = r.db.ID(id).Update(existing)
	return err
}

// PatchWithFilter 带自定义过滤的Patch
func (r *Repository[T]) PatchWithFilter(id int64, updateData map[string]interface{}, filterFunc func(map[string]interface{}) map[string]interface{}) error {
	// 过滤更新数据
	filteredData := filterFunc(updateData)

	existing, err := r.GetByID(id)
	if err != nil {
		return err
	}

	if err := utils.PatchUpdate(existing, filteredData, []string{}); err != nil {
		return err
	}

	_, err = r.db.ID(id).Update(existing)
	return err
}

// GetManyWithFilters 带筛选条件的分页查询
func (r *Repository[T]) GetManyWithFilters(filters map[string]interface{}, page, pageSize int) ([]T, int64, error) {
	var entities []T = make([]T, 0)
	session := r.db.NewSession()

	// 应用筛选条件
	if len(filters) > 0 {
		for field, value := range filters {
			if err := r.addFilterCondition(session, field, value); err != nil {
				return nil, 0, err
			}
		}
	}

	total, err := session.Count(new(T))
	if err != nil {
		return nil, 0, err
	}

	// 重新应用筛选条件
	if len(filters) > 0 {
		for field, value := range filters {
			if err := r.addFilterCondition(session, field, value); err != nil {
				return nil, 0, err
			}
		}
	}

	if page > 0 && pageSize > 0 {
		session = session.Limit(pageSize, (page-1)*pageSize)
	}

	err = session.Find(&entities)
	if err != nil {
		return nil, 0, err
	}

	return entities, total, nil
}

// GetManyWithFilters 带筛选条件的分页查询
func (r *Repository[T]) GetAllWithFilters(filters map[string]interface{}) ([]T, error) {
	var entities []T
	session := r.db.NewSession()

	// 应用筛选条件
	if len(filters) > 0 {
		for field, value := range filters {
			if err := r.addFilterCondition(session, field, value); err != nil {
				return nil, err
			}
		}
	}

	err := session.Find(&entities)
	if err != nil {
		return nil, err
	}

	return entities, nil
}

// addFilterCondition 添加筛选条件（修复版）
func (r *Repository[T]) addFilterCondition(session *xorm.Session, field string, value interface{}) error {
	var model T
	modelType := reflect.TypeOf(model)

	// 如果model是指针类型，获取其元素类型
	if modelType.Kind() == reflect.Ptr {
		modelType = modelType.Elem()
	}

	// 查找匹配的字段（支持字段名和json tag）
	var foundField *reflect.StructField
	for i := 0; i < modelType.NumField(); i++ {
		f := modelType.Field(i)

		// 1. 检查字段名是否匹配
		if strings.EqualFold(f.Name, field) {
			foundField = &f
			break
		}

		// 2. 检查json tag是否匹配
		if jsonTag := f.Tag.Get("json"); jsonTag != "" {
			// 解析json tag（处理omitempty等选项）
			jsonName := strings.Split(jsonTag, ",")[0]
			if jsonName != "" && jsonName == field {
				foundField = &f
				break
			}

			// 3. 检查xorm tag（可选）
			if xormTag := f.Tag.Get("xorm"); xormTag != "" {
				if strings.Contains(xormTag, field) {
					foundField = &f
					break
				}
			}
		}
	}

	// 如果找到匹配的字段，根据字段类型决定筛选方式
	if foundField != nil {
		switch foundField.Type.Kind() {
		case reflect.String:
			// 字符串字段使用LIKE筛选
			if strValue, ok := value.(string); ok {
				session.Where(foundField.Name+" LIKE ?", "%"+strValue+"%")
			} else {
				session.Where(foundField.Name+" = ?", value)
			}
			return nil
		default:
			// 其他类型使用相等筛选
			session.Where(foundField.Name+" = ?", value)
			return nil
		}
	}

	// 如果找不到匹配的字段，使用原始字段名（兼容性处理）
	session.Where(field+" = ?", value)
	return nil
}
